package cn.buk.tms.dao;

import cn.buk.tms.entity.order.flight.FlightCatchOrder;
import cn.buk.tms.entity.order.flight.FlightCatchOrderFlight;
import cn.buk.tms.entity.misc.OperationLog;
import cn.buk.tms.entity.order.flight.FlightCatchOrderFlight_;
import cn.buk.tms.entity.order.flight.FlightCatchOrder_;
import cn.buk.tms.factory.OperationLogFactory;
import cn.buk.tms.sc.SearchFlightOrderCriteria;
import cn.buk.common.util.DateUtil;
import java.util.ArrayList;
import java.util.List;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Order;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.Subquery;
import jakarta.transaction.Transactional;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Component;

import static cn.buk.tms.common.constant.TmsOrderConstant.OPERATING_OBJECT_FLIGHT_ORDER;

/**
 * @author yfdai
 */
@Component
@Transactional
public class FlightCatchOrderDaoImpl extends AbstractDao implements FlightCatchOrderDao {

    private static final Logger logger = LogManager.getLogger(FlightCatchOrderDaoImpl.class);

	@Override
  public int createOrder(FlightCatchOrder o, final String username) {
        em.persist(o);

        OperationLog log = createFlightOrderLog(o.getEnterpriseId(), o.getId(), username, "创建订单");
        em.persist(log);

        return o.getId();
    }


    @Override
    public int updatePassenger(int enterpriseId, int orderId, int id, String name, String idNo, String ffpNo, String mobile) {
        int retCode = 0;

        retCode = em.createQuery("update FlightCatchOrderPassenger o set " +
                "o.name = :name, o.idNo = :idNo, o.ffpNo = :ffpNo, o.mobile = :mobile " +
                "where o.id = :id and o.enterpriseId = :enterpriseId and o.order.id = :orderId")
                .setParameter("id", id)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("orderId", orderId)
                .setParameter("name", name)
                .setParameter("idNo", idNo)
                .setParameter("ffpNo", ffpNo)
                .setParameter("mobile", mobile)
                .executeUpdate();

        return retCode;
    }

    @Override
    public int updateRemark(int enterpriseId, String username, int orderId, String remark) {
        int retCode = 0;

        retCode = em.createQuery("update FlightCatchOrder o set " +
                "o.remark = :remark, o.lastUpdate = :lastUpdate " +
                "where o.id = :id and o.enterpriseId = :enterpriseId and o.status <> :status")
                .setParameter("id", orderId)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("remark", remark)
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .setParameter("status", FlightCatchOrder.STATUS_DONE)
                .executeUpdate();

        if (retCode == 1) {
            OperationLog log = createFlightOrderLog(enterpriseId, orderId, username, "备注修改为：" + remark);
            em.persist(log);
        }

        return retCode;
    }

    @Override
    public int updatePnr(int enterpriseId, String username, int orderId, String pnrNo) {
        int retCode = 0;

        retCode = em.createQuery("update FlightCatchOrder o set " +
                "o.newPnrNo = :pnr, o.status = :newStatus, o.lastUpdate = :lastUpdate " +
                "where o.id = :id and o.enterpriseId = :enterpriseId")
                .setParameter("id", orderId)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("pnr", pnrNo)
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .setParameter("newStatus", FlightCatchOrder.STATUS_DONE)
                .executeUpdate();

        if (retCode == 1) {
            OperationLog log = createFlightOrderLog(enterpriseId, orderId, username, "保存新编码 " + pnrNo);
            em.persist(log);
        }

        return retCode;
    }

    /**
     * 取消机票订单
     */
    @Override
    public int cancelFlightOrder(int enterpriseId, String username, int orderId, int reasonCode, String reasonDesc) {
        int retCode = 0;

        retCode = em.createQuery("update FlightCatchOrder o set " +
                "o.status = :newStatus, o.lastUpdate = :lastUpdate " +
                "where o.id = :id and o.enterpriseId = :enterpriseId")
                .setParameter("id", orderId)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("newStatus", FlightCatchOrder.STATUS_CANCELED)
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .executeUpdate();

        if (retCode == 1) {
            String content = "取消订单: " + reasonDesc;
            if (reasonCode > 0) {
              content += "(" + reasonCode + ")";
            }

            OperationLog log = createFlightOrderLog(enterpriseId, orderId, username, content);
            em.persist(log);
        }

        return retCode;
    }



    @Override
    public List<OperationLog> searchHistory(int enterpriseId, int orderId) {
            return em.createQuery("select o from OperationLog o " +
                    "where o.enterpriseId = :enterpriseId and o.orderId = :orderId and o.objectType = :ot", OperationLog.class)
                    .setParameter("enterpriseId", enterpriseId)
                    .setParameter("orderId", orderId)
                    .setParameter("ot", OPERATING_OBJECT_FLIGHT_ORDER)
                    .getResultList();
    }

    @Override
    public int monitorFlightCatchOrder(int enterpriseId, String username, int orderId) {
        int retCode = 0;

        retCode = em.createQuery("update FlightCatchOrder o set " +
                "o.status = :newStatus, o.lastUpdate = :lastUpdate " +
                "where o.id = :id and o.enterpriseId = :enterpriseId")
                .setParameter("id", orderId)
                .setParameter("enterpriseId", enterpriseId)
                .setParameter("newStatus", FlightCatchOrder.STATUS_WAITING)
                .setParameter("lastUpdate", DateUtil.getCurDateTime())
                .executeUpdate();

        if (retCode == 1) {
            String content = "重新开始监控. ";

            OperationLog log = createFlightOrderLog(enterpriseId, orderId, username, content);
            em.persist(log);
        }


        return retCode;
    }

    @Override
    public int deleteCatchOrder(int enterpriseId, int orderId) {
        int retCode;


        FlightCatchOrder order = em.find(FlightCatchOrder.class, orderId);
        if (order == null || order.getEnterpriseId() != enterpriseId) {
          throw new RuntimeException("FlightCatchOrder is not exist.");
        }

        em.remove(order);


        retCode = 1;

        return retCode;
    }

    private OperationLog createFlightOrderLog(int enterpriseId, int orderId, String username, String remark) {
        OperationLog log = OperationLogFactory.createFlightCatchOrderOperationLog();
        log.setEnterpriseId(enterpriseId);
        log.setOrderId(orderId);
        log.setOperator(username);
        log.setContent(remark);
        return log;
    }


    @Override
    public FlightCatchOrder getOrder(int id) {
            FlightCatchOrder order = em.find(FlightCatchOrder.class, id);
            if (order == null) {
              return null;
            }

            order.getPassengers().size();
            order.getFlights().size();


            return order;
    }


    @Override
    public List<FlightCatchOrder> searchOrder(int enterpriseId, String username, SearchFlightOrderCriteria sc) {
        List<FlightCatchOrder> results = null;

        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<FlightCatchOrder> cq = cb.createQuery(FlightCatchOrder.class);
        Root<FlightCatchOrder> root = cq.from(FlightCatchOrder.class);
        root.alias("o");

        var predicates0 = getPredicates_searchOrder(enterpriseId, sc, cb, root, cq);


        //计算根据条件查询得出的数据总数
        CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
        Root<FlightCatchOrder> countRoot = countQuery.from(FlightCatchOrder.class);
        countRoot.alias("o");

        var predicates1 = getPredicates_searchOrder(enterpriseId, sc, cb, countRoot, cq);

        // count items
        countQuery.select(cb.count(countRoot)).where(predicates1.toArray(new Predicate[predicates1.size()]));
        Long count = em.createQuery(countQuery).getSingleResult();

        //查询
        cq.select(root).where(predicates0.toArray(new Predicate[predicates0.size()]));

        List<Order> orderByes = new ArrayList<>();
        orderByes.add(cb.desc(root.get("id")));

        cq.orderBy(orderByes);

        int maxResults = count.intValue();
        if (maxResults > 0) {
            sc.getPage().setRowCount(maxResults);

            results = em.createQuery(cq)
                    .setFirstResult(sc.getPage().getFirstPosition())
                    .setMaxResults(sc.getPage().getPageSize())
                    .getResultList();

            for (FlightCatchOrder order : results) {
                order.getFlights().size();
                order.getPassengers().size();
            }

        }
        if (results == null) {
          results = new ArrayList<>();
        }

        return results;
    }

    private static List<Predicate> getPredicates_searchOrder(int enterpriseId, SearchFlightOrderCriteria sc, CriteriaBuilder cb, Root<FlightCatchOrder> root, CriteriaQuery<FlightCatchOrder> cq) {
        List<Predicate> predicates = new ArrayList<>();

        Predicate predicate = cb.conjunction();
        predicates.add(predicate);

        predicate = cb.equal(root.get(FlightCatchOrder_.enterpriseId), enterpriseId);
        predicates.add(predicate);

        if (sc.getStatus() > -1) {
            predicate = cb.equal(root.get(FlightCatchOrder_.status), sc.getStatus());
            predicates.add(predicate);
        }


        if (sc.getIntlTicket() >= 0) {
            predicate = cb.equal(root.get(FlightCatchOrder_.intlTicket), sc.getIntlTicket());
            predicates.add(predicate);
        }

        if (sc.getBeginDate() != null) {
          predicate = cb.greaterThanOrEqualTo(root.get(FlightCatchOrder_.createTime), sc.getBeginDate());
          predicates.add(predicate);
        }


        Subquery<FlightCatchOrderFlight> subQuery = null;

        if (sc.getDepartureDate() != null && sc.getDepartureDate().length() == 10) {
            //
            subQuery = cq.subquery(FlightCatchOrderFlight.class);
            Root<FlightCatchOrderFlight> subRoot = subQuery.from(FlightCatchOrderFlight.class);
            subQuery.select(subRoot);
            subQuery.alias("s");

            List<Predicate> subQueryPredicates = new ArrayList<>();
            subQueryPredicates.add(cb.equal(root.get(FlightCatchOrder_.id), subRoot.get(FlightCatchOrderFlight_.order)));

            subQueryPredicates.add(cb.equal(subRoot.get(FlightCatchOrderFlight_.flight).get("departureDate"), sc.getDepartureDate()));

            subQuery.where(subQueryPredicates.toArray(new Predicate[]{}));
        }

        if (subQuery != null) {
            predicates.add(cb.exists(subQuery));
        }
        return predicates;
    }

}
